#!/usr/local/bin/python2.5

"""

A Phased Array Processor Interface for the SMA
written by Rurik Primiani
with help from....

Aaron Parsons: who wrote ibob_serial, which has been modified here
   to include a close() member function to free up the serial port.
   The style of the commented class titles have also been taken from
   Aaron's python codes :)
   
"""

from __future__ import division
import sys
import serial
import struct
import shelve
from math import floor, pi, sin, cos, atan2
from time import sleep, time, gmtime
from socket import socket, AF_INET, SOCK_STREAM

from matplotlib.pyplot import plot, subplot, figure, xlim, ylim, ion, ioff
#from Gnuplot import Gnuplot
from numpy import max, zeros
from rpyc import Service

sys.path.append('/SVN/sma-vlbi')
from ibob_serial import IBOBSerial
from paUtils import *
from dDS_clnt import *

# A pylab color macro
colors = ['b','g', 'r', 'c', 'm', 'y', 'k', 'w']

# A lookup table for reading hb/walsh capture data
states = { int('000' + '0000000' + '0000000' + '0000000' + '0000001',2):(0,0,0,0,1),
           int('000' + '0000000' + '0000000' + '0000001' + '0000000',2):(0,0,0,1,0),
           int('000' + '0000000' + '0000000' + '0000001' + '0000001',2):(0,0,0,1,1),
           int('000' + '0000000' + '0000001' + '0000000' + '0000000',2):(0,0,1,0,0),
           int('000' + '0000000' + '0000001' + '0000000' + '0000001',2):(0,0,1,0,1),
           int('000' + '0000000' + '0000001' + '0000001' + '0000000',2):(0,0,1,1,0),
           int('000' + '0000000' + '0000001' + '0000001' + '0000001',2):(0,0,1,1,1),
           int('000' + '0000001' + '0000000' + '0000000' + '0000000',2):(0,1,0,0,0),
           int('000' + '0000001' + '0000000' + '0000000' + '0000001',2):(0,1,0,0,1),
           int('000' + '0000001' + '0000000' + '0000001' + '0000000',2):(0,1,0,1,0),
           int('000' + '0000001' + '0000000' + '0000001' + '0000001',2):(0,1,0,1,1),
           int('000' + '0000001' + '0000001' + '0000000' + '0000000',2):(0,1,1,0,0),
           int('000' + '0000001' + '0000001' + '0000000' + '0000001',2):(0,1,1,0,1),
           int('000' + '0000001' + '0000001' + '0000001' + '0000000',2):(0,1,1,1,0),
           int('000' + '0000001' + '0000001' + '0000001' + '0000001',2):(0,1,1,1,1),
           int('001' + '0000000' + '0000000' + '0000000' + '0000000',2):(1,0,0,0,0),
           int('001' + '0000000' + '0000000' + '0000000' + '0000001',2):(1,0,0,0,1),
           int('001' + '0000000' + '0000000' + '0000001' + '0000000',2):(1,0,0,1,0),
           int('001' + '0000000' + '0000000' + '0000001' + '0000001',2):(1,0,0,1,1),
           int('001' + '0000000' + '0000001' + '0000000' + '0000000',2):(1,0,1,0,0),
           int('001' + '0000000' + '0000001' + '0000000' + '0000001',2):(1,0,1,0,1),
           int('001' + '0000000' + '0000001' + '0000001' + '0000000',2):(1,0,1,1,0),
           int('001' + '0000000' + '0000001' + '0000001' + '0000001',2):(1,0,1,1,1),
           int('001' + '0000001' + '0000000' + '0000000' + '0000000',2):(1,1,0,0,0),
           int('001' + '0000001' + '0000000' + '0000000' + '0000001',2):(1,1,0,0,1),
           int('001' + '0000001' + '0000000' + '0000001' + '0000000',2):(1,1,0,1,0),
           int('001' + '0000001' + '0000000' + '0000001' + '0000001',2):(1,1,0,1,1),
           int('001' + '0000001' + '0000001' + '0000000' + '0000000',2):(1,1,1,0,0),
           int('001' + '0000001' + '0000001' + '0000000' + '0000001',2):(1,1,1,0,1),
           int('001' + '0000001' + '0000001' + '0000001' + '0000000',2):(1,1,1,1,0),
           int('001' + '0000001' + '0000001' + '0000001' + '0000001',2):(1,1,1,1,1),
           int('000' + '0000000' + '0000000' + '0000000' + '0000000',2):(0,0,0,0,0),
           }

#
# A class that returns delay values for the current
# antenna configuration using parameters provided by
# the SMA dDS computer over RPCs
#

class SMAInterface:
    def __init__(self, 
                 dds_host='128.171.116.189',
                 ):
        self.dds_host = dds_host
        self.ph = phaseOffsetsClass()
        self.ddsClient = DDSClient(dds_host)
        
    def queryDDS(self, phases={0:0}):
        self.ph.setPhases(phases)
        res = self.ddsClient.ddsPAPUpdate(self.ph)
        self.source_RA = res.rA
        self.latitude = res.refLat
        self.longitude = res.refLong
        self.altitude = res.refRad
        self.antExists = res.antennaExists
        self.a = res.a
        self.b = res.b
        self.c = res.c

class DummySMAInterface:
    def __init__(self, 
                 dds_host='128.171.116.189',
                 ):
        self.dds_host = dds_host
        
    def queryDDS(self):
        self.source_RA = -1.5
        self.latitude = 1.5
        self.longitude = 0
        self.altitude = 0
        self.antExists = [1]*8
        self.a = [2000*10**-9]+[(2000-300.0)*10**-9]*7
        self.b = [0]+[10*10**-7]*7
        self.c = [0]+[10**-9]*7

class DelayTracker:
    def __init__(self,
                 sma,
                 antennas=(0,1,2,3,4,5,6,7,8,9,10), 
                 ):
        self.sma = sma
        self.antennas = antennas
        self.delays = {}

    def getLST(self, t=time()):
        """
        Follows the procedure outlined in
            Practical Astronomy with your Calculator
            by Peter Duffet-Smith
         to find the (L)ocal (S)idereal (T)time
        """
        #
        # First, find the Julian date (page 7)
        #
        (y,m,d,hours,mins,sec,week,jd,dst) = gmtime(t)
        ut_hours = hours + (mins + sec/60.)/60.
        d = d + ut_hours/24.
        if m==1 or m==2:
            y -= 1
            m += 12
        A = int(y/100.)
        B = 2. - A + int(A/4.)
        C = int(365.25*y)
        D = int(30.600100*(m+1))
        jd = B + C + D + int(d) + 1720994.500
        #
        # Next find Greenwich mean sidereal time
        # using procedure on page 17
        #
        s = jd - 2451545.0
        t = s/36525.0
        t0 = 6.697374558 + 2400.051336*t + 0.000025862*t**2
        t0 = (t0 - int(t0/24.)*24)
        if t0<0.0:
            t0 += 24.
        ut = 1.002737909*ut_hours
        tmp = int((ut+t0)/24.)
        gmst = ut + t0 - tmp*24.
        # 
        # Finally, find the LST using page 20
        #
        long_tdiff = (self.sma.longitude*(180/pi))/15.
        lst = gmst + long_tdiff
        if lst>24:
            lst = lst-24
        if lst<0:
            lst = lst+24
        return lst

    def getHourAngle(self, t=time()):
        return self.getLST(t)*(pi/12) - self.sma.source_RA

    def getDelays(self, t=time()):
        H = self.getHourAngle(t)
        for ant in self.antennas:
            self.delays[ant] = round(3000.0 - (10.0**9)*(+self.sma.a[ant]+\
                                     self.sma.b[ant]*cos(H)+\
                                     self.sma.c[ant]*sin(H)),
                                     1)
        return self.delays

    def formatTime(self, dec_time):
        hours = int(dec_time)
        mins = int((dec_time - hours)*60.)
        sec = (dec_time - hours - mins/60.)*3600.
        return '%i:%02i:%2.2f' % (hours,abs(mins),abs(sec))


class PhaseShifter:
    def __init__(self, port):
        self.ser = serial.Serial(port, 115200)
        self.ser.flush()

    def do(self, cmd, arg1=0, arg2=0):
        self.ser.flush()
        self.ser.write(struct.pack('<3H',cmd, arg1, arg2))
        while struct.unpack('<3H',self.ser.read(6))!=(cmd,arg1,arg2):
            self.ser.write(struct.pack('<H',2))
            self.ser.write(struct.pack('<3H',cmd, arg1, arg2))
            print "Verification error, trying again"
        self.ser.write(struct.pack('<H',1))

    def startWalsh(self):
        self.do(2,0,0)

    def stopWalsh(self):
        self.do(3,0,0)

    def setPhase(self, ant, pha, tries=3):
        for i in range(tries):
            self.do(1,ant,pha)

        
##########################################################
#  ____     _            ____                            #
# |  _ \   | |          / ___}                _          #
# | | \ \__| |___ _   _| |  ___ ___ __ __ __ | |_ _ ___  #
# | | | /_ \ |_  \ | | | | |   |  _| _|_ \ _}   _| |  _| #
# | |/ / __/ |_|  |\/ /|  \|_o | || |  __/|_ | | o | |   #
# |___/\___/_|__|_|  /  \____}_|_||_|\___/__}|_|___|_|   #
#               |___/                                    #
##########################################################

class DelayCorrector:
    def __init__(self, port):
        self.comport = port
        self.interface = {  'capt'   : (int('D2008000', 16), 'L'),
                            'delay0' : (int('D0000400', 16), 'L'),
                            'delay1' : (int('D0000500', 16), 'L'),
                            'delay2' : (int('D0000600', 16), 'L'),
                            'delay3' : (int('D0000700', 16), 'L'),
                            'fdelay0': (int('D0000800', 16), 'L'),
                            'fdelay1': (int('D0000900', 16), 'L'),
                            'fdelay2': (int('D0000A00', 16), 'L'),
                            'fdelay3': (int('D0000B00', 16), 'L'),
                            'gain0'  : (int('D0000C00', 16), 'L'),
                            'gain1'  : (int('D1000000', 16), 'L'),
                            'gain2'  : (int('D1000100', 16), 'L'),
                            'gain3'  : (int('D1000200', 16), 'L'),
                            'reset'  : (int('D1000300', 16), 'L'),
                            'select0': (int('D1000400', 16), 'L'),
                            'select1': (int('D1000500', 16), 'L'),
                            'select2': (int('D1000600', 16), 'L'),
                            'select3': (int('D1000700', 16), 'L'),
                            'smasel' : (int('D1000800', 16), 'L'),
                            'xaui'   : (int('D1000900', 16), 'L'),
                            'sum_out': (int('D1000A00', 16), 'L'),
                            'thresh0': (int('D1000B00', 16), 'L'),
                            'thresh1': (int('D1000C00', 16), 'L'),
                            'thresh2': (int('D1000D00', 16), 'L'),
                            'thresh3': (int('D1000E00', 16), 'L'),
                            'valid'  : (int('D1000F00', 16), 'L'),
                            'walsel' : (int('D1001000', 16), 'L'),
                            'xaui0ld': (int('D2000000', 16), 'L'),
                            'xaui1ld': (int('D2000100', 16), 'L'),
                            'cpt_en' : (int('D2000200', 16), 'L'),
                            'cpt_rst': (int('D2000300', 16), 'L'),
                            }
        self.params = {'delay0'  : 500,
                       'delay1'  : 500,
                       'delay2'  : 500,
                       'delay3'  : 500,
                       'fdelay0' : 0,
                       'fdelay1' : 0,
                       'fdelay2' : 0,
                       'fdelay3' : 0,
                       'select0' : 3,
                       'select1' : 3,
                       'select2' : 3,
                       'select3' : 3,
                       'gain0'   : 128,
                       'gain1'   : 128,
                       'gain2'   : 128,
                       'gain3'   : 128,
                       'thresh0' : 30,
                       'thresh1' : 30,
                       'thresh2' : 30,
                       'thresh3' : 30,
                       }
        self.cntrls = {'reset'   : 0,
                       'smasel'  : 0,
                       'xaui'    : 1,
                       'valid'   : 15,
                       'walsel'  : 0,
                       'cpt_en'  : 0,
                       'cpt_rst' : 0,
                       }
        self.devices = {}
        self.types = {}
        for i in self.interface:
            self.devices[i], self.types[i] = self.interface[i]
        self.ibob = IBOBSerial(self.devices, self.types, port)

    def read(self, dev, num):
        val = self.ibob.read(dev,num)
        return val

    def write(self, dev, num, size=1):
        self.ibob.write(dev,num)
        if self.ibob.read(dev,size)==num:
            return None
        else:
            return "Err: Readback failed"

    def start(self):
        for p in self.params:
            self.ibob.write(p,self.params[p])
        for c in self.cntrls:
            self.ibob.write(c,self.cntrls[c])

    def setDelays(self, delays={0:16.0,1:16.0,2:16.0,3:16.0}):
        for d in delays:
            if delays[d]<16.0:
                raise Exception, "Channel "+str(d)+\
                      ": Delay value must be greater than 16."
            de = 'delay'+str(d)
            fe = 'fdelay'+str(d)
            se = 'select'+str(d)
            dly = (delays[d]/0.9765625)*10
            self.params[de] = floor(floor(dly/10)/4)
            self.params[fe] = floor((dly-(floor(dly/10)*10)))
            self.params[se] = 3-floor(dly/10)%4
            self.write(de,self.params[de])
            self.write(fe,self.params[fe])
            self.write(se,self.params[se])

    def setThresholds(self, thresholds={0:16,1:16,2:16,3:16}):
        for t in thresholds:
            th = 'thresh'+str(t)
            self.params[th] = thresholds[t]
            self.ibob.write(th,self.params[th])

    def setGains(self, gains={0:0,1:0,2:0,3:0}):
        for g in gains:
            ga = 'gain'+str(g)
            self.params[ga] = gains[g]
            self.ibob.write(ga,self.params[ga])

    def getDelays(self, channels=[0,1,2,3]):
        delays = []
        for ch in channels:
            de = 'delay'+str(ch)
            fe = 'fdelay'+str(ch)
            se = 'select'+str(ch)
            if self.ibob.read(de,1)!=self.params[de]:
                print de+": hardware/software mismatch, updating software value."
                self.params[de] = self.ibob.read(de,1)
            if self.ibob.read(fe,1)!=self.params[fe]:
                print fe+": hardware/software mismatch, updating software value."
                self.params[fe] = self.ibob.read(fe,1)
            if self.ibob.read(se,1)!=self.params[se]:
                print se+": hardware/software mismatch, updating software value."
                self.params[se] = self.ibob.read(se,1)
            delay = self.params[de]*4 + 3-self.params[se] + 0.1*self.params[fe]
            delays.append(delay*0.9765625)
        return delays

    def getCapture(self, samples=8192):
        hb = []
        w1 = []
        w2 = []
        w3 = []
        w4 = []
        self.write('cpt_rst',1)
        self.write('cpt_rst',0)
        self.write('cpt_en',1)
        sleep(1)
        self.write('cpt_en',0)
        for i in self.read('capt',samples):
            temp = states[i]
            hb.append(temp[0])
            w1.append(temp[1])
            w2.append(temp[2])
            w3.append(temp[3])
            w4.append(temp[4])
        return {'hb':tuple(hb),
                'w1':tuple(w1),
                'w2':tuple(w2),
                'w3':tuple(w3),
                'w4':tuple(w4)}
        
    
    def checkXAUI(self):
        linkdown0 = self.ibob.read('xaui0ld',1)
        linkdown1 = self.ibob.read('xaui1ld',1)
        return (linkdown0,linkdown1)

    def close(self):
        self.ibob.write('valid',0)
        self.ibob.write('xaui',0)
        self.ibob.close_ibob()


##########################################################
#   ____             ____              _                 #
#  / ___}           / ___}            | |     _          #
# | |   ___ _ __ __| |   ___ ___ __ __| |___ | |_ _ ___  #
# | |  |  _| | _| _| |  |   |  _| _|_ \ |_  \   _| |  _| #
# |  \_|_| o |__ \_ \ \_|_o | || |  __/ |_|  | | o | |   #
#  \_____}___|___/__/_____}_|_||_|\___/_|__|_|_|___|_|   #
#                                                        #
##########################################################

class DummyCrossCorrelator:
    def __init__(self, host="fake", port=11111):
        self.host = host
        self.port = port
    def cmd(self, command):
        return None
    def read_reg(self, reg):
        return None
    def read_corr(self, bram):
        return None
    def correlate(self, int_time):
        return None
    def getCorrFunc(self):
        out = []
        for b in range(7):
            out.append(list(randArray(32,100000,50000)))
        return out        

class CrossCorrelator:
    def __init__(self, host="sma-bee2.cfa.harvard.edu", port=4500):
        self.host = host
        self.port = port

    def cmd(self, command):
        size = 1024
        s = socket(AF_INET, SOCK_STREAM)
        s.connect((self.host,self.port))
        s.send(command)
        result = s.recv(size)
        s.close()
        return result
    
    def read_reg(self, reg):
        val = self.cmd('read_reg:'+reg)
        return int(val)

    def read_corr(self, bram):
        strval = self.cmd('read_bram:'+bram+':4:32')
        val = []
        for i in strval.split(','):
                val.append(int(i))
        return val

    def correlate(self, int_time):
        self.cmd('correlate:'+str(int_time))

    def getCorrFunc(self):
        baselines = []
        for j in range(7):
            bram = "corr_out"+str(j)
            val = self.read_corr(bram)
            baselines.append(val)
        return baselines


##########################################################
#  ____ _                     _  ___                     #
# |  _  \|                   | |/   \                    #
# | |_| /|___ ___  __  ____ _| |  _  \___ __ __ _   _    #
# |  __/  _  |_  \/ _|/ __ \_  | |_| |  _| _|  \ | | |   #
# | |  | | | |_|  |__ \  __/_| |  _  | || ||_|  |\/ /    #
# |_|  |_| |_|__|_|___/\___/___|_| |_|_||_|___|_|  /     #
#                                             |___/      #
##########################################################

class PhasedArray:
    def __init__(self,
                 dec1_com = "/dev/ttyS4",
                 dec2_com = "/dev/ttyS5",
                 corr_host = "128.171.116.127",
                 corr_port = 4500,
                 phase_com = "/dev/ttyS10",
                 ):
        self.dec1 = DelayCorrector(dec1_com)
        self.dec2 = DelayCorrector(dec2_com)
        self.corr = CrossCorrelator(corr_host,corr_port)
        #self.phase = PhaseShifter(phase_com)
        self.dec1.cntrls['smasel'] = 2
        self.dec2.cntrls['walsel'] = 1
        self.dec1.params['gain1'] = 0
        self.dec1.start()
        self.dec2.start()
        self.hist0 = { '01'      : 0,
                       '00'      : 0,
                       '10'      : 0,
                       '11'      : 0, }
        self.h0_cnt = 0
        self.hist1 = { '01'      : 0,
                       '00'      : 0,
                       '10'      : 0,
                       '11'      : 0, }
        self.h1_cnt = 0
        self.hist2 = { '01'      : 0,
                       '00'      : 0,
                       '10'      : 0,
                       '11'      : 0, }
        self.h2_cnt = 0
        self.hist3 = { '01'      : 0,
                       '00'      : 0,
                       '10'      : 0,
                       '11'      : 0, }
        self.h3_cnt = 0
        self.hist4 = { '01'      : 0,
                       '00'      : 0,
                       '10'      : 0,
                       '11'      : 0, }
        self.h4_cnt = 0
        self.hist5 = { '01'      : 0,
                       '00'      : 0,
                       '10'      : 0,
                       '11'      : 0, }
        self.h5_cnt = 0
        self.hist6 = { '01'      : 0,
                       '00'      : 0,
                       '10'      : 0,
                       '11'      : 0, }
        self.h6_cnt = 0
        self.hist7 = { '01'      : 0,
                       '00'      : 0,
                       '10'      : 0,
                       '11'      : 0, }
        self.h7_cnt = 0
        self.corrs = []
        self.getDelays()
        self.doffsets = { 0 : 0.0,
                          1 : 0.0,
                          2 : 0.0,
                          3 : 0.0,
                          4 : 0.0,
                          5 : 0.0,
                          6 : 0.0,
                          7 : 0.0, }
        self.N = 0

    def correlations(self, baselines=range(7)):
        out = []
        for i in baselines:
            out.append(self.corrs[i])
        return out

    def getDelays(self):
        delays = {}
        dec1_del = self.dec1.getDelays()
        dec2_del = self.dec2.getDelays()
        for i in range(len(dec1_del)):
            delays[i] = dec1_del[i]
        for i in range(len(dec2_del)):
            delays[i+4] = dec2_del[i]
        self.delays = delays

    def getHistograms(self):
        print "Needs to be rewritten."

    def getCorrelations(self, int_time):
        self.corr.correlate(int_time)
        sleep(int_time)
        self.corrs = self.corr.getCorrFunc()

    def getCaptures(self, samples=8192):
        capt1 = self.dec1.getCapture(samples)
        capt2 = self.dec2.getCapture(samples)
        return capt1,capt2

    def setDelays(self, delays):
        dec1_delays = {}
        dec2_delays = {}
        for a,d in delays.iteritems():
            if a in (0,1,2,3):
                dec1_delays[a] = d
            if a in (4,5,6,7):
                dec2_delays[a-4] = d
        self.dec1.setDelays(dec1_delays)
        self.dec2.setDelays(dec2_delays)

    def setGains(self, gains):
        dec1_gains = {}
        dec2_gains = {}
        for a,g in gains.iteritems():
            if a in (0,1,2,3):
                dec1_gains[a] = g
            if a in (4,5,6,7):
                dec2_gains[a-4] = g
        self.dec1.setGains(dec1_gains)
        self.dec2.setGains(dec2_gains)


def pack_dict(dict):
    out = []
    for i,v in dict.iteritems():
        out.append( (i, v) )
    return tuple(out)

def unpack_tup(tup):
    out = {}
    for i in range(len(tup)):
        out[tup[i][0]] = tup[i][1]
    return out

def hb_freq(tup):
    flag = 0
    num = 0.0
    den = 0
    count = 0.0
    for i in range(len(tup)):
        if tup[i] is 1 and tup[i-1] is 0:
            flag += 1
            if flag>1:
                #print flag, count
                num += count
                den += 1
            count = 0.0
        else:
            count += 1
    return 256000000/((num/den)*20000)

if __name__=="__main__":
    import sys
    #sma = SMAInterface('128.171.116.189')
    if sys.argv[1]=='server':
        if sys.argv[2]=='dummy':
            pa = DummyPhasedArray()
	    print "Starting dummy server..."
        else:
            pa = PhasedArray()
            print "Starting the phased array server..."
            sleep(30)
        class data_buf:
            def __init__(self):
                self.N = 0
                self.correlations = []
                self.real = []
                self.imag = []
                self.phases = []
                self.magnitudes = []
                self.phasefits = []
                self.fit_params = []
                self.phoffsets = {0:0.0,
                                  1:0.0,
                                  2:0.0,
                                  3:0.0,
                                  4:0.0,
                                  5:0.0,
                                  6:0.0,
                                  7:0.0,
                                  8:0.0,
                                  9:0.0,
                                  10:0.0,
                                  }
                c = []
                re = []
                im = []
                p = []
                m = []
                pf = []
                for i in range(32):
                    c.append(0)
                for i in range(16):
                    re.append(0.0)
                    im.append(0.0)
                    p.append(0.0)
                    m.append(0.0)
                    pf.append(0.0)
                for i in range(7):
                    self.correlations.append(tuple(c))
                    self.real.append(tuple(re))
                    self.imag.append(tuple(im))
                    self.phases.append(tuple(p))
                    self.magnitudes.append(tuple(m))
                    self.phasefits.append(tuple(pf))
                    self.fit_params.append((0,0))
        pad = data_buf()
        class PhasedArrayService(Service):
            def on_connect(self):
                print "**** new connection ****"
            def on_disconnect(self):
                print "**** connection lost or terminated ****"
            def exposed_startCorrelation(self, int_time):
                # This will simply send the correlator the signal
                # to start correlating, freeing up the phased array
                # to do other things
                print "**** startCorrelation ****"
                pa.corr.correlate(int_time)
                for i in range(7):
                    if pad.N!=0:
                        c = pa.corrs[i]
                        pad.correlations[i] = tuple(c)
                        pad.real[i] = tuple(getPhase(corrReorder(c))[0])
                        pad.imag[i] = tuple(getPhase(corrReorder(c))[1])
                        pad.phases[i] = tuple(getPhase(corrReorder(c))[2])
                        pad.magnitudes[i] = tuple(getMagnitude(corrReorder(c)))
                        thefit = getPhaseFit(dewrap(pad.phases[i]))
                        pad.phasefits[i] = tuple(thefit[1])
                        pad.fit_params[i] = tuple(thefit[0])
                #print type(pad.correlations[i][0])
                #print type(pad.phases[i][0])
                #print type(pad.magnitudes[i][0])
                phase_log = shelve.open('phase.log')
                phase_log[str(time())] = pad.fit_params
                phase_log.close()
                return (pad.N, tuple(pad.correlations), tuple(pad.phases), tuple(pad.magnitudes), tuple(pad.phasefits), tuple(pad.fit_params))
            def exposed_retrieveCorrelation(self):
                print "**** retrieveCorrelation ****"
                pa.corrs = pa.corr.getCorrFunc()
                pad.N = pad.N + 1
            def exposed_getCorrelations(self, int_time):
                # This will stall the phased array until
                # the correlator finishes
                print "**** getCorrelations ****"
                pa.getCorrelations(int_time)
            def exposed_padata(self, baselines=range(7)):
                print "**** padata ****"
                return (pad.N, tuple(pad.correlations), tuple(pad.phases), tuple(pad.magnitudes), tuple(pad.phasefits), tuple(pad.fit_params))
            def exposed_getDelays(self, antennas=range(8)):
                print "**** getDelays ****"
                pa.getDelays()
                return pack_dict(pa.delays)
            def exposed_doffsets(self, antennas=range(8)):
                print "**** doffsets ****"
                return pack_dict(pa.doffsets)
            def exposed_getCaptures(self, samples=8192):
                capt1, capt2 = pa.getCaptures(samples)
                return tuple((pack_dict(capt1),pack_dict(capt2)))
            def exposed_setDelays(self, dtuple):
                print "**** setDelays ****"
                delays = unpack_tup(dtuple)
                s = "{"
                for a,d in delays.iteritems():
                    delays[a] = d + pa.doffsets[a]
                    s += str(a)+":"+"%.1f"%d+", "
                print s+"}"
                pa.setDelays(delays)
            def exposed_setDelayOffsets(self, doff_tuple):
                print "**** setDelayOffsets ****"
                doffsets = unpack_tup(doff_tuple)
                s = "{"
                for a,d in doffsets.iteritems():
                    pa.doffsets[a] = d
                    s += str(a)+":"+"%.1f"%d+", "
                print s+"}"
            def exposed_setGains(self, gtuple):
                print "**** setGains ****"
                gains = unpack_tup(gtuple)
                s = "{"
                for a,g in gains.iteritems():
                    gains[a] = g
                    s += str(a)+":"+"%.1f"%g+", "
                print s+"}"
                pa.setGains(gains)
            def exposed_phoffsets(self):
                return pack_dict(pad.phoffsets)
            def exposed_phaseUp(self, baselines, mode='offsets'):
                delays = pa.delays
                doffsets = pa.doffsets
                new_delays = {}
                del_diff = {}
                for b in baselines:
                    slope = pad.fit_params[b][0]
                    pad.phoffsets[b+1] = pad.phoffsets[b+1] + pad.fit_params[b][1]
                    del_diff[b+1] = doffsets[b+1] + (10**9)*(slope*(16/512000000)/(2*pi))
                    new_delays[b+1] = delays[b+1] + del_diff[b+1]
                if mode is 'offsets':
                    self.exposed_setDelayOffsets(pack_dict(del_diff))
                else:
                    pa.setDelays(new_delays)
                #sma.queryDDS(phases)
            def exposed_getVecAvg(self, baselines=range(7)):
                out = {}
                real_sum = {}
                imag_sum = {}
                for b in baselines:
                    real_sum[b] = sum(pad.real[b][1:3])
#                    print pad.real[b]
                    imag_sum[b] = sum(pad.imag[b][1:3])
#                    print pad.imag[b]
#                    print real_sum[b], imag_sum[b]
                    out[b] = float(atan2(imag_sum[b],real_sum[b]))
                    print out[b]
                return pack_dict(out)
        from rpyc.utils.server import ThreadedServer
        t = ThreadedServer(PhasedArrayService, port = 18861)
        t.start()
    elif sys.argv[1]=='delaytracker' and sys.argv[2] and sys.argv[3]:
        from rpyc import connect
        dds_host = sys.argv[2]
        period = float(sys.argv[3])
        palow = connect('localhost',18861)
        # pahgh = connect('localhost',18862)
        sma = SMAInterface(dds_host=dds_host)
        # sma = DummySMAInterface(dds_host=dds_host)
        dt = DelayTracker(sma)
        while True:
            if palow.root.getTracking():
                tstart = time()
                phoffsets = unpack_tup(palow.root.phoffsets())
                phout = {}
                for a in phoffsets:
                    phout[a] = phoffsets[a]
                phout[6] = 0.0
                phout[1] = phoffsets[1]
                phout[2] = phoffsets[2]
                phout[3] = phoffsets[3]
                phout[4] = phoffsets[4]
                phout[5] = phoffsets[5]
                phout[7] = phoffsets[7]
                phout[8] = phoffsets[8]
                sma.queryDDS(phout)
                delays = dt.getDelays(tstart+period)
                print delays
                if time()>(tstart+period): 
                    raise Exception,"Period is too short"
                while time()<(tstart+period): tnow=time()
                out = {}
                for a,d in delays.iteritems():
                    if a==6:
                        out[0] = d
                    elif a==1:
                        out[1] = d
                    elif a==2:
                        out[2] = d
                    elif a==3:
                        out[3] = d
                    elif a==4:
                        out[4] = d
                    elif a==5:
                        out[5] = d
                    elif a==7:
                        out[6] = d
                    elif a==8:
                        out[7] = d
                    else:
                        print "skipping "+str(a)
                print out
                palow.root.setDelays(pack_dict(out))
                # pahgh.root.setDelays(pack_dict(out))
                print "LST: "+dt.formatTime(dt.getLST(tstart+period))+", RA: "+dt.formatTime(sma.source_RA*(12/pi))
                print "Hour angle: "+dt.formatTime((12/pi)*dt.getHourAngle(tstart+period))
                print "Delays updated, actual period: "+str(time()-tstart)
                print "**************************************************"

